package worker

import (
	"context"
	"crontab/common"
	clientv3 "go.etcd.io/etcd/client/v3"
	"log"
	"net"
	"time"
)

var (
	G_Register *Register
)

type Register struct {
	Client *clientv3.Client
	Kv clientv3.KV
	Lease clientv3.Lease
	LocalIp string  // 本机IP
}

func (r *Register) ServiceRegister() {
	var (
		leaseGrantResp *clientv3.LeaseGrantResponse
		err error
		leaseKeepRespChan <- chan *clientv3.LeaseKeepAliveResponse
		leaseKeepResp *clientv3.LeaseKeepAliveResponse
		regKey string
		ctx context.Context
		cancelFunc context.CancelFunc
	)
	regKey = common.ETCD_JOB_REGISTER_DIR + r.LocalIp
	// 不断去进行注册
	for {
		cancelFunc = nil
		// 创建租约
		leaseGrantResp,err = r.Lease.Grant(context.TODO(),10)
		if err != nil {
			// 失败随眠5s后继续重试
			goto ERR
		}

		ctx,cancelFunc = context.WithCancel(context.TODO())
		// 自动续租
		leaseKeepRespChan,err = r.Lease.KeepAlive(ctx,leaseGrantResp.ID)
		if err != nil {
			goto ERR
		}
		//log.Printf(regKey)
		// 服务注册
		_,err = r.Kv.Put(context.TODO(),regKey,"",clientv3.WithLease(leaseGrantResp.ID))
		if err != nil {
			goto ERR
		}

		for {
			select {
			case leaseKeepResp = <- leaseKeepRespChan:
				if leaseKeepResp == nil {
					// 自动续租失败
					goto ERR
				}
			}
		}

		// 本地循环错误,随眠一下,继续重试
		ERR:
		r.ServiceRegisterFailSleep()
		// 如果失败取消自动续租
		if cancelFunc != nil {
			cancelFunc()
		}
	}
}

// 服务注册失败后,随眠几秒然后重试
func (r *Register) ServiceRegisterFailSleep() {
	time.Sleep(time.Second * 5)
}

// 获取IPv4地址
func getLocalIps() (ipv4Addrs []string) {
	var (
		addrs []net.Addr
		err error
		ipnet *net.IPNet
		ok bool
	)
	ipv4Addrs = make([]string,0)
	addrs,err = net.InterfaceAddrs()
	if err != nil {
		log.Printf("获取IP地址失败," + err.Error())
		return
	}
	for _, addr := range addrs {
		// 反解成IP地址,且不为本地回环地址
		if ipnet,ok = addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			// 是IP地址
			// ipnet 转为IPV4地址,如果转成功则为IPV4地址
			if ipnet.IP.To4() != nil {
				// 转ipv4地址成功
				ipv4Addrs = append(ipv4Addrs,ipnet.IP.String())
			}
		}
	}
	return
}

func InitRegister() (err error) {
	var (
		register *Register
		ipAddrs []string
	)
	register = &Register{
		Client: G_EtcdJob.EtcdClient,
		Kv:     G_EtcdJob.EtcdKv,
		Lease:  G_EtcdJob.EtcdLease,
	}
	// 获取本机IP
	ipAddrs = getLocalIps()
	if len(ipAddrs) == 0 {
		err = common.ERR_IP_NOT_FOUND
		return
	}
	register.LocalIp = ipAddrs[0]
	//fmt.Println(ipAddrs)

	G_Register = register

	// 起一个协程,去进行服务注册
	go G_Register.ServiceRegister()
	return
}